package com.cgs.query.remote.http

import com.cgs.query.exception.QueryException
import com.cgs.query.handler.HELLO_METHOD
import com.cgs.query.service.IQueryService
import com.cgs.query.util.CastUtils
import com.cgs.query.util.GsonUtils
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import mu.KotlinLogging
import org.apache.commons.lang3.ClassUtils
import org.apache.commons.lang3.ObjectUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import javax.servlet.http.HttpServletRequest

private val logger = KotlinLogging.logger { }

@RestController
@RequestMapping("/remote")
@Api(description = "Http调用接口")
class HttpRemoteController {

    @Autowired
    private lateinit var queryService: IQueryService

    private val methods = IQueryService::class.java.methods

    @PostMapping
    @ApiOperation(value = "定义服务")
    fun defineService(@ApiParam(value = "参数：{method_name:,args:}", required = true) @RequestBody param: Map<String, Any>, request: HttpServletRequest) =
            invoke(param, queryService, request)

    private fun invoke(param: Map<String, Any>, bean: Any, request: HttpServletRequest): Any? {

        val name = param["method_name"]

        return when (name) {
            HELLO_METHOD -> {
                HELLO_METHOD
            }
            "ping" -> {
                "pong"
            }
            else -> {
                val args = param["args"]

                if (ObjectUtils.allNotNull(name, args)) {

                    val method = methods.firstOrNull { it.name == name }
                            ?: throw QueryException("不支持的方法:[$name]")

                    val arrayArgs = GsonUtils.gson.fromJson(args as String, List::class.java).toTypedArray()

                    if (method.parameterTypes.size == arrayArgs.size) {
                        method.parameterTypes.forEachIndexed { index, it ->
                            arrayArgs[index] = CastUtils.cast(arrayArgs[index], it)
                        }
                        logger.info { "服务远程调用:[$name , $args ],来自于： ${request.getHeader("from")}" }

                        try {
                            return method.invoke(bean, *arrayArgs)
                        } catch (e: Exception) {
                            throw e.cause ?: e
                        }
                    }
                    throw QueryException("参数[args]数量不匹配")
                }
                throw QueryException("参数[method_name][args]不能为空")
            }
        }
    }
}